import { kernel, model, schema } from '@/ts/base';
import { IApplication, IFileInfo, IGroup, IReport, ITarget, IWork } from '@/ts/core';
import { AssignStatusType, AssignType, NodeType, PeriodType } from '@/ts/base/enum';
import {
  XAssignTask,
  XAssignTaskTree,
  XCells,
  XReport,
  XSheet,
  XWorkInstance,
} from '@/ts/base/schema';
import { AssignTaskTree, IAssignTaskTree } from '@/ts/core/work/assignTree';
import orgCtrl from '@/ts/controller';
import { IAssignTaskModel } from '@/ts/core/thing/standard/assignTaskModel';
import { message } from 'antd';
import { FileInfo } from '@/ts/core/thing/fileinfo';
import { Work } from '@/ts/core/work/index';
import { LoadOptions, SummaryAssignTaskView, TaskContent } from '@/ts/base/model';
import { Application } from '@/ts/core/thing/standard/application';
import { excelCellRef } from '@/components/DataStandard/NewReportForm/Utils';
import _ from 'lodash';
import { deepClone } from '@/ts/base/common';
import { entityOperates } from '@/ts/core/public';
import { formatDate } from '@/utils';

export interface IAssignTask extends IFileInfo<schema.XAssignTask> {
  /** 键 */
  key: string;
  /** 操作空间 */
  target: ITarget;
  /** 提交任务集群空间 */
  assignGroup: IGroup | undefined;
  /** 分发任务集群空间 */
  distGroup: IGroup | undefined;
  /** 数据时期 */
  period: string;
  /** 任务状态 */
  taskStatus: AssignStatusType;
  /** 任务内容 */
  assignContent: model.TaskContent | undefined;
  /** 分发内容 */
  distContent: model.TaskContent | undefined;
  /** 分发类型 */
  assignType: AssignType;
  /** 任务模板 */
  assignTaskModel?: IAssignTaskModel;
  /** 分发树 */
  assignTaskTree: IAssignTaskTree | undefined;
  /** 分发集群任务树 */
  distAssignTaskTree: IAssignTaskTree | undefined;
  /** 办事对象 */
  work: IWork | undefined;
  /** 当前树 */
  currentTree: IAssignTaskTree | undefined;
  /** 当前空间 */
  currentSpace: IGroup | undefined;

  /** 分发任务 */
  distAssignTask(distContend?: TaskContent): Promise<boolean>;
  /** 接收任务 */
  receiveAssignTask(): Promise<schema.XAssignTask | undefined>;
  /** 上报任务 */
  submitAssignTask(instanceId: string): Promise<boolean>;
  /** 加载任务树 */
  loadTree(reload?: boolean): Promise<IAssignTaskTree | undefined>;
  /** 加载分发树 */
  loadAssignTree(reload?: boolean): Promise<IAssignTaskTree | undefined>;
  /** 加载分发任务集群空间任务树 */
  loadDistAssignTree(reload?: boolean): Promise<IAssignTaskTree | undefined>;
  /** 加载办事信息 */
  loadWork(reload?: boolean, isDistWork?: boolean): Promise<IWork | undefined>;
  /** 加载办事实例 */
  loadInstanceDetail(instanceId: string): Promise<XWorkInstance | undefined>;
  /** 变更 */
  change(): Promise<boolean>;
  /** 保存草稿 ID */
  draft(id: string): Promise<schema.XAssignTask | undefined> | undefined;
  /** 取消接收 */
  cancelReceive(): Promise<boolean> | undefined;
  /** 属性值穿透 */
  propertySummaryDrill(
    cell: XCells,
    sheet: XSheet,
    form: XReport,
  ): Promise<SummaryAssignTaskView>;
  /** 下级节点汇总 */
  summary(isLeafSummary?: boolean): Promise<Dictionary<Partial<schema.XEntity>>>;
  /** 计算任务接收对应的往期任务时期 */
  getHistoryPeriod(timeSpan: number): string;
}

export class AssignTask extends FileInfo<schema.XAssignTask> implements IAssignTask {
  constructor(metadata: schema.XAssignTask, target: ITarget) {
    super(metadata, target.directory);
    this.distContent = metadata.distContent;
    this.assignType = metadata.assignType;
    this.assignContent = metadata.assignContent;
    if (this.metadata.assignContent?.sessionId) {
      this.assignGroup = [...target.targets, ...target.space.targets].find(
        (t) => t.id == this.metadata.assignContent?.sessionId,
      ) as IGroup;
    }
    if (this.metadata.distContent?.sessionId) {
      this.distGroup = [...target.targets, ...target.space.targets].find(
        (t) => t.id == this.metadata.distContent?.sessionId,
      ) as IGroup;
    }
  }

  assignContent: model.TaskContent | undefined;
  assignTaskModel: IAssignTaskModel | undefined;
  assignTaskTree: IAssignTaskTree | undefined;
  distAssignTaskTree: IAssignTaskTree | undefined;
  assignType: AssignType;
  distContent: model.TaskContent | undefined;
  assignGroup: IGroup | undefined;
  distGroup: IGroup | undefined;
  work: IWork | undefined;
  currentSpace: IGroup | undefined;
  currentTree: IAssignTaskTree | undefined;

  private _workLoaded = false;
  private _treeLoaded: boolean = false;
  private _distTreeLoaded: boolean = false;

  get code() {
    return this.metadata.period;
  }

  get name() {
    return '[' + this.period + ']' + this.metadata.assignName;
  }

  get cacheFlag() {
    return 'assign-task';
  }

  get period() {
    return this.metadata.period;
  }

  get taskStatus() {
    return this.metadata.taskStatus;
  }

  get groupTags() {
    const tags: string[] = [
      this.metadata.nodeTypeName,
      this.metadata.name,
      this.metadata.periodType,
    ];
    if (this.metadata.assignType) {
      tags.push(this.metadata.assignType === AssignType.ALL ? '全部分发' : '逐级分发');
    }
    if (this.metadata.isAutoFill) {
      tags.push('自动补全');
    }
    return tags;
  }

  override operates(): model.OperateModel[] {
    const operates = [];
    operates.push(entityOperates.Open, entityOperates.Delete);
    return operates;
  }

  async distAssignTask(distContent?: TaskContent): Promise<boolean> {
    // 判断当前任务是否需要分发
    if (
      this.metadata.nodeType !== NodeType.Summary ||
      (AssignType.ALL === this.assignType && !this.metadata.modelId)
    ) {
      message.error('当前节点类型无需分发');
      return false;
    }
    // 判断子任务节点是否存在分发内容
    if (AssignType.STEP === this.assignType && !distContent) {
      message.error('分发内容不能为空');
      return false;
    }
    // 子任务节点赋值分发内容
    if (distContent) {
      this.distContent = distContent;
      if (distContent?.sessionId) {
        this.distGroup = [...this.target.targets, ...this.target.space.targets].find(
          (t) => t.id == distContent.sessionId,
        ) as IGroup;
      }
    }
    if (!this.distGroup) {
      message.error('请选择分发集群');
      return false;
    }
    // 查询任务树
    if (!this.assignTaskTree) {
      await this.loadAssignTree();
    }
    // 生成任务树到下发集群空间
    await this.distGroup.resource.assignTaskTreeColl.replace(
      <XAssignTaskTree>this.assignTaskTree?.taskTreeData,
    );
    // 判断分发类型,生成任务节点到公共空间
    const assignTreeNodes = (await this.assignTaskTree?.loadSubNodes(
      this.id,
    )) as XAssignTask[];
    switch (this.assignType) {
      case AssignType.ALL:
        {
          assignTreeNodes.map((node) => {
            if (node.id === this.id) {
              node.distContent = deepClone(this.distContent);
              node.taskStatus = AssignStatusType.ASSIGNED;
              return;
            }
            // 初始化节点信息
            node.assignType = AssignType.ALL;
            node.periodType = this.metadata.periodType;
            node.period = this.period;
            node.assignContent = deepClone(this.distContent);
            node.taskStatus = AssignStatusType.EMPTY;
            node.typeName = '任务';
            node.assignName = this.metadata.assignName;
          });
        }
        break;
      case AssignType.STEP:
        {
          // 加载直属节点
          assignTreeNodes.map((node) => {
            if (node.id === this.id) {
              node.distContent = deepClone(this.distContent);
              node.taskStatus = AssignStatusType.ASSIGNED;
              return;
            }
            if (node.parentId !== this.id) return;
            // 初始化节点信息
            node.assignType =
              node.nodeType === NodeType.Summary ? AssignType.STEP : AssignType.ALL;
            node.periodType = this.metadata.periodType;
            node.period = this.period;
            node.assignContent = deepClone(this.distContent);
            node.distContent = deepClone(this.distContent);
            if (node.distContent?.sessionId) {
              node.distContent.sessionId = undefined;
            }
            node.taskStatus = AssignStatusType.EMPTY;
            node.typeName = '任务';
            node.assignName = this.metadata.assignName;
          });
        }
        break;
    }
    // 判断当前任务空间是否为发送任务的空间
    let isSameBelong = false;
    if (this.target.belongId == this.distGroup?.belongId) {
      let thisStoreId = this.target.storeId || this.target.space.storeId;
      let destStoreId = this.distGroup.storeId || this.distGroup.space.storeId;
      if (thisStoreId == destStoreId) {
        isSameBelong = true;
      }
    }
    if (!isSameBelong) {
      // 拷贝办事、报表
      const applications = await this.target.resource.applicationColl.find([
        this.distContent?.applicationId,
      ]);
      if (!applications || applications.length <= 0) {
        message.error('请绑定办事');
        return false;
      }
      const application = new Application(applications[0], this.target.directory);
      await application.copy(this.distGroup.directory);
    }
    // 批量更新
    const batchSize = 300;
    const concurrencyLimit = 5;
    const insertPromises = [];

    for (let i = 0; i < assignTreeNodes.length; i += batchSize) {
      const batch = assignTreeNodes.slice(i, i + batchSize);
      insertPromises.push(
        this.distGroup.resource.assignTaskPublicColl.replaceMany(batch),
      );
      if (insertPromises.length >= concurrencyLimit) {
        await Promise.all(insertPromises);
        insertPromises.length = 0;
      }
    }
    if (insertPromises.length > 0) {
      await Promise.all(insertPromises);
    }
    // 更新任务状态
    this.metadata.taskStatus = AssignStatusType.ASSIGNED;
    this.metadata.distContent = deepClone(this.distContent);
    await this.target.resource.assignTaskPublicColl.replace(this.metadata);
    return Promise.resolve(true);
  }

  async receiveAssignTask(): Promise<XAssignTask | undefined> {
    // 任务接收时间限制
    const curDate = new Date();
    const startDate = this.assignContent?.startDate
      ? new Date(this.assignContent.startDate)
      : null;
    const endDate = this.assignContent?.endDate
      ? new Date(this.assignContent.endDate)
      : null;
    if (startDate && endDate && (curDate < startDate || curDate > endDate)) {
      message.error('当前任务已过期');
      return;
    }
    if (!this.assignGroup || this.assignGroup.id !== this.target.id) {
      message.error('当前任务空间不支持接收');
      return;
    }
    const company = orgCtrl.user.companys.find((c) => c.id == this.metadata.belongId);
    if (!company) {
      message.error('找不到当前节点的接收单位');
      return;
    }
    if (!this.assignTaskTree) {
      const tree = await this.loadAssignTree(true);
      if (!tree) {
        message.error('找不到分发树形');
        return;
      }
    }
    // 更新任务状态
    this.metadata.taskStatus = AssignStatusType.RECEIVED;
    this.metadata.receiveUserId = orgCtrl.user.id;
    await this.target.resource.assignTaskPublicColl.replace(this.metadata);
    return this.metadata;
  }

  async submitAssignTask(instanceId: string): Promise<boolean> {
    this.metadata.instanceId = instanceId;
    this.metadata.taskStatus = AssignStatusType.SUBMITTED;
    await this.target.resource.assignTaskPublicColl.replace(this.metadata);
    if (!this.assignGroup) {
      throw new Error('任务上报集群未找到');
    }
    await this.assignGroup.resource.assignTaskPublicColl.replace(this.metadata);
    // 判断当前节点是否汇总节点且为逐级分发
    if (
      this.metadata.nodeType === NodeType.Summary &&
      AssignType.STEP === this.assignType
    ) {
      if (!this.distGroup) {
        throw new Error('找不到分发集群');
      }
      // 查询子树数据
      const newNodes = await this.distAssignTaskTree?.loadSubNodes(this.id, true);
      // 子树上传集群临时空间
      if (newNodes && newNodes.length > 0) {
        await this.assignGroup.resource.assignTaskPublicColl.replaceMany(newNodes);
      }
      // 查询任务下发集群空间中的things
      this.work?.forms.map(async (form) => {
        if (!this.distGroup || !this.assignGroup) {
          throw new Error('找不到上报集群');
        }
        const distThingColl = this.distGroup.resource.genTargetColl(
          form.thingColl.collName,
        );
        const submitThingColl = this.assignGroup.resource.genTargetColl(
          `-${form.thingColl.collName}`,
        );
        const things = await distThingColl.loadSpace({
          options: {
            match: {
              period: this.metadata.period,
              treeId: this.metadata.treeId,
            },
          },
        });
        // 上传things到集群临时空间
        await submitThingColl.replaceMany(things);
      });
    }
    return true;
  }

  async change(): Promise<boolean> {
    this.metadata.receiveUserId = this.userId;
    this.metadata.previousInstanceId = this.metadata.instanceId;
    this.metadata.isReject = false;
    this.metadata.taskStatus = AssignStatusType.RECEIVED;
    delete this.metadata.instanceId;
    const data = await this.target.resource.assignTaskPublicColl.replace(this.metadata);
    return !!data;
  }

  async draft(id: string): Promise<XAssignTask | undefined> {
    this.metadata.draftId = id;
    return await this.target.resource.assignTaskPublicColl.replace(this.metadata);
  }

  async cancelReceive(): Promise<boolean> {
    if (this.metadata.receiveUserId !== orgCtrl.user.id) {
      message.warn('不是当前任务接收人');
      return false;
    }
    this.metadata.receiveUserId = '';
    this.metadata.taskStatus = AssignStatusType.EMPTY;
    this.metadata.draftId = '';
    this.metadata.instanceId = '';
    this.metadata.previousInstanceId = '';
    await this.target.resource.assignTaskPublicColl.replace(this.metadata);
    return true;
  }

  override async delete(): Promise<boolean> {
    if (
      this.metadata.nodeType !== NodeType.Summary ||
      this.metadata.receiveUserId !== orgCtrl.user.id
    ) {
      message.warn('当前任务不支持删除');
      return false;
    }
    if (
      this.distGroup &&
      this.distContent?.treeId &&
      (this.metadata.assignType == AssignType.STEP || this.metadata.modelId)
    ) {
      // 删除当前任务
      await this.target.resource.assignTaskPublicColl.remove(this.metadata);
      // 删除分发集群任务
      const update = {
        _set_: {
          isDeleted: true,
        },
      };
      const match = {
        treeId: this.distContent?.treeId,
      };
      await this.distGroup.resource.assignTaskTreeColl.update(
        this.distContent?.treeId,
        update,
      );
      await this.distGroup.resource.assignTaskPublicColl.updateMatch(match, update);
    }
    if (this.assignGroup) {
      const update = {
        _set_: {
          receiveUserId: '',
          taskStatus: AssignStatusType.EMPTY,
        },
      };
      const newVar = await this.assignGroup.resource.assignTaskPublicColl.update(
        this.id,
        update,
      );
      return newVar !== undefined;
    }
    return true;
  }

  async loadWork(reload?: boolean, isDistWork?: boolean): Promise<IWork | undefined> {
    if (reload || !this._workLoaded) {
      this._workLoaded = true;
      if (this.metadata.modelId || isDistWork) {
        const res = await this.target.resource.workDefineColl.loadResult({
          options: {
            match: {
              primaryId: this.metadata.distContent?.workId,
              applicationId: {
                _gt_: '0',
              },
              isDeleted: false,
            },
          },
        });
        if (res.success && res.data.length == 1) {
          const work = new Work(res.data[0], {
            directory: this.target.directory,
          } as IApplication);
          if (work) {
            this.work = work as IWork;
            return this.work;
          }
        }
      }
      if (!this.assignGroup) {
        message.error('找不到任务空间，无法加载办事');
        return;
      }
      const res = await this.assignGroup.resource.workDefineColl.loadResult({
        options: {
          match: {
            primaryId: this.metadata.assignContent?.workId,
            // shareId: this.metadata.assignContent?.sessionId,
            applicationId: {
              _gt_: '0',
            },
            isDeleted: false,
          },
        },
      });
      if (res.success && res.data.length == 1) {
        const work = new Work(res.data[0], {
          directory: this.assignGroup.directory,
        } as IApplication);
        if (work) {
          this.work = work as IWork;
          return this.work;
        }
      }
    }
    return this.work;
  }

  async loadInstanceDetail(instanceId: string): Promise<XWorkInstance | undefined> {
    const belongId = this.metadata.belongId;
    let detail = await kernel.findInstance(
      this.assignContent?.sessionId,
      belongId,
      instanceId,
    );
    if (!detail) {
      detail = await kernel.findInstance(belongId, belongId, instanceId);
    }
    if (detail) {
      detail.tasks = await kernel.LoadInstanceTask(detail.shareId, belongId, instanceId);
    }
    return detail;
  }

  async loadTree(): Promise<IAssignTaskTree | undefined> {
    if (this.metadata.nodeType !== NodeType.Summary) {
      return;
    }
    const { modelId, assignType, taskStatus } = this.metadata;
    if (
      (modelId || assignType === AssignType.STEP) &&
      taskStatus === AssignStatusType.RECEIVED
    ) {
      // 加载当前空间任务树,用于分发
      this.currentTree = await this.loadAssignTree();
      return this.currentTree;
    }
    if (assignType === AssignType.STEP || (assignType === AssignType.ALL && modelId)) {
      // 加载下发集群公共空间任务树
      this.currentTree = await this.loadDistAssignTree();
      this.currentSpace = this.distGroup;
    } else {
      // 加载上报集群公共空间任务树
      this.currentTree = await this.loadAssignTree();
    }
    return this.currentTree;
  }

  /**
   * 当前空间任务树
   * 加载主界面左侧树数据
   * @param reload
   */
  async loadAssignTree(reload?: boolean): Promise<IAssignTaskTree | undefined> {
    if (reload || !this._treeLoaded) {
      const assignTree = await this.target.resource.assignTaskTreeColl.loadSpace({
        options: {
          match: {
            id: this.metadata.treeId,
            isDeleted: false,
          },
        },
      });
      if (assignTree && assignTree.length > 0) {
        this.assignTaskTree = new AssignTaskTree(
          assignTree[0],
          this.target?.directory,
          this.target.resource.assignTaskTreeColl,
          this.target.resource.assignTaskPublicColl,
        );
        this._treeLoaded = true;
      }
    }
    return this.assignTaskTree;
  }

  /**
   * 集群空间任务树
   * 加载主界面左侧树数据
   * @param reload
   */
  async loadDistAssignTree(reload?: boolean): Promise<IAssignTaskTree | undefined> {
    if (!this.distGroup) {
      message.error('当前任务未分发');
      return;
    }
    if (reload || !this._distTreeLoaded) {
      const assignTree = await this.distGroup?.resource.assignTaskTreeColl?.loadSpace({
        options: {
          match: {
            id: this.metadata.treeId,
            isDeleted: false,
          },
        },
      });
      if (assignTree && assignTree.length > 0 && this.distGroup) {
        this.distAssignTaskTree = new AssignTaskTree(
          assignTree[0],
          this.distGroup.directory,
          this.distGroup.resource.assignTaskTreeColl,
          this.distGroup.resource.assignTaskPublicColl,
        );
        this._distTreeLoaded = true;
      }
    }
    return this.distAssignTaskTree;
  }

  async propertySummaryDrill(
    cell: XCells,
    sheet: XSheet,
    form: XReport,
  ): Promise<SummaryAssignTaskView> {
    if (this.metadata.nodeType != NodeType.Summary) {
      throw new Error('当前节点不可汇总');
    }
    if (!this.currentTree) {
      const distTree = await this.loadTree();
      if (!distTree) {
        throw new Error('找不到树形');
      }
      this.currentTree = distTree;
    }
    let result: SummaryAssignTaskView = {
      ...this.metadata,
      children: [],
      value: 0,
    };

    const children = (await this.currentTree.loadChildren(this.id)) as XAssignTask[];
    if (children.length == 0) {
      return result;
    }

    const loadOptions: LoadOptions<schema.XThing> = {
      options: {
        match: {
          period: this.period,
          assignId: {
            _in_: children.map((i) => i.id),
          },
          isDeleted: false,
        },
      },
    };
    const thingColl = form.collName
      ? this.currentTree.directory.resource.genColl<schema.XThing>(form.collName)
      : this.currentTree.directory.resource.thingColl;
    const list = await thingColl.loadSpace(loadOptions);

    const detailMap = list.reduce<Dictionary<schema.XThing>>((map, row) => {
      map[row.assignId] = row;
      return map;
    }, {});
    const cellRef = excelCellRef({ row: cell.row, col: cell.col });
    for (const child of children) {
      const childWithValue: SummaryAssignTaskView = {
        ...child,
        children: [],
        value: null,
      };
      const data = detailMap[child.id] || {};
      if (data['R' + sheet.attributeId]) {
        childWithValue.value = data['R' + sheet.attributeId][cellRef] ?? '';
      }
      result.children.push(childWithValue);
    }
    result.value = _.sumBy(result.children, (c) => c.value || 0);

    return result;
  }

  async summary(isLeafSummary?: boolean): Promise<Dictionary<Partial<schema.XEntity>>> {
    if (this.metadata.nodeType != NodeType.Summary) {
      throw new Error('当前节点不可汇总');
    }
    const result: Dictionary<Partial<schema.XEntity>> = {};
    if (!this.currentTree) {
      const distTree = await this.loadTree();
      if (!distTree) {
        throw new Error('找不到树形');
      }
      this.currentTree = distTree;
    }
    if (!this.work) {
      const work = await this.loadWork(true);
      if (!work) {
        throw new Error('找不到办事');
      }
      this.work = work;
    }
    const children = isLeafSummary
      ? ((await this.currentTree.loadSubNodes(this.id, true))?.filter(
          (v) => v.nodeType === NodeType.Normal,
        ) as XAssignTask[])
      : ((await this.currentTree.loadChildren(this.id)) as XAssignTask[]);
    if (children.length == 0) {
      return result;
    }
    const forms = [...this.work.primaryForms, ...this.work.detailForms];
    for (const form of forms) {
      const ids = children.flatMap((item) => {
        return item.thingId?.[form.id] || [];
      });
      if (ids.length <= 0) {
        return result;
      }
      let summary: { [p: string]: number | object } | undefined = {};
      const item: any = {};
      if (form.metadata.typeName == '表格') {
        const reportForm = form as IReport;
        summary = await reportForm.loadSheetSummary({ ids });
        for (const field of reportForm.objectFields) {
          if (summary) {
            item[field.id] = summary[field.code];
          }
        }
      }
      if (!summary) {
        throw new Error(`汇总 ${form.name} 失败`);
      }
      result[form.id] = item;
    }
    return result;
  }

  getHistoryPeriod(timeSpan = -1) {
    const period = this.metadata.period;
    const date = new Date(period);
    const year = date.getFullYear();
    const month = date.getMonth();
    const day = date.getDate();

    switch (this.metadata.periodType) {
      case PeriodType.Year:
        return year + timeSpan + '';
      case PeriodType.Quarter: {
        const newDate = new Date(year, month + timeSpan * 3, 1);
        return formatDate(newDate, 'yyyy-MM');
      }
      case PeriodType.Month: {
        const newDate = new Date(year, month + timeSpan, 1);
        return formatDate(newDate, 'yyyy-MM');
      }
      case PeriodType.Day: {
        const newDate = new Date(year, month, day + timeSpan);
        return formatDate(newDate, 'yyyy-MM-dd');
      }
      case PeriodType.Week: {
        const newDate = new Date(year, month, day + 7 * timeSpan);
        return formatDate(newDate, 'yyyy-MM-dd');
      }
      case PeriodType.Once:
      case PeriodType.Any:
      default:
        return period;
    }
  }
}
